1000 #include "asm.h"
1001 
1002 # Start the first CPU: switch to 32-bit protected mode, jump into C.
1003 # The BIOS loads this code from the first sector of the hard disk into
1004 # memory at physical address 0x7c00 and starts executing in real mode
1005 # with %cs=0 %ip=7c00.
1006 
1007 #define SEG_KCODE 1  // kernel code
1008 #define SEG_KDATA 2  // kernel data+stack
1009 
1010 #define CR0_PE    1  // protected mode enable bit
1011 
1012 .code16                       # Assemble for 16-bit mode
1013 .globl start
1014 start:
1015   cli                         # Disable interrupts
1016 
1017   # Set up the important data segment registers (DS, ES, SS).
1018   xorw    %ax,%ax             # Segment number zero
1019   movw    %ax,%ds             # -> Data Segment
1020   movw    %ax,%es             # -> Extra Segment
1021   movw    %ax,%ss             # -> Stack Segment
1022 
1023   # Enable A20:
1024   #   For backwards compatibility with the earliest PCs, physical
1025   #   address line 20 is tied low, so that addresses higher than
1026   #   1MB wrap around to zero by default.  This code undoes this.
1027 seta20.1:
1028   inb     $0x64,%al               # Wait for not busy
1029   testb   $0x2,%al
1030   jnz     seta20.1
1031 
1032   movb    $0xd1,%al               # 0xd1 -> port 0x64
1033   outb    %al,$0x64
1034 
1035 seta20.2:
1036   inb     $0x64,%al               # Wait for not busy
1037   testb   $0x2,%al
1038   jnz     seta20.2
1039 
1040   movb    $0xdf,%al               # 0xdf -> port 0x60
1041   outb    %al,$0x60
1042 
1043   # Switch from real to protected mode, using a bootstrap GDT
1044   # and segment translation that makes virtual addresses
1045   # identical to physical addresses, so that the
1046   # effective memory map does not change during the switch.
1047   lgdt    gdtdesc
1048   movl    %cr0, %eax
1049   orl     $CR0_PE, %eax
1050   movl    %eax, %cr0
1051 
1052   # This ljmp is how you load the CS (Code Segment) register.
1053   # SEG_ASM produces segment descriptors with the 32-bit mode
1054   # flag set (the D flag), so addresses and word operands will
1055   # default to 32 bits after this jump.
1056   ljmp    $(SEG_KCODE<<3), $start32
1057 
1058 .code32                       # Assemble for 32-bit mode
1059 start32:
1060   # Set up the protected-mode data segment registers
1061   movw    $(SEG_KDATA<<3), %ax    # Our data segment selector
1062   movw    %ax, %ds                # -> DS: Data Segment
1063   movw    %ax, %es                # -> ES: Extra Segment
1064   movw    %ax, %ss                # -> SS: Stack Segment
1065   movw    $0, %ax                 # Zero segments not ready for use
1066   movw    %ax, %fs                # -> FS
1067   movw    %ax, %gs                # -> GS
1068 
1069   # Set up the stack pointer and call into C.
1070   movl    $start, %esp
1071   call    bootmain
1072 
1073   # If bootmain returns (it shouldn't), trigger a Bochs
1074   # breakpoint if running under Bochs, then loop.
1075   movw    $0x8a00, %ax            # 0x8a00 -> port 0x8a00
1076   movw    %ax, %dx
1077   outw    %ax, %dx
1078   movw    $0x8ae0, %ax            # 0x8ae0 -> port 0x8a00
1079   outw    %ax, %dx
1080 spin:
1081   jmp     spin
1082 
1083 # Bootstrap GDT
1084 .p2align 2                                # force 4 byte alignment
1085 gdt:
1086   SEG_NULLASM                             # null seg
1087   SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)   # code seg
1088   SEG_ASM(STA_W, 0x0, 0xffffffff)         # data seg
1089 
1090 gdtdesc:
1091   .word   (gdtdesc - gdt - 1)             # sizeof(gdt) - 1
1092   .long   gdt                             # address gdt
1093 
1094 
1095 
1096 
1097 
1098 
1099 
